
#include "SQLSelectParser.h"
#include "SQLExprParser.h"
#include "../../utils/FnvHash.h"
#include "../ast/statement/SQLValuesQuery.h"
#include "../../utils/instanceof.h"
#include "../../utils/log.h"
#include "../../utils/StringUtils.h"
#include "../../utils/encode_util.h"
#include "../ast/statement/SQLValuesTableSource.h"
#include "../ast/statement/SQLUnionQueryTableSource.h"
#include "../ast/statement/SQLJoinTableSource.h"
#include "../ast/statement/SQLSubqueryTableSource.h"
#include "../dialect/hive/parser/HiveCreateTableParser.h"
#include "../dialect/hive/stmt/HiveCreateTableStatement.h"
#include "../ast/SQLAdhocTableSource.h"
#include "../ast/statement/SQLUnnestTableSource.h"
#include "../ast/statement/SQLExprHint.h"
#include "../ast/statement/SQLLateralViewTableSource.h"
#include "../ast/expr/SQLSizeExpr.h"

SQLSelectParser::SQLSelectParser(string_ptr theSql)
    : super(theSql)
{
  // LOG_INFO << ", in SQLSelectParser::SQLSelectParser, constructor step 1" << std::endl;
  // super(sql);
  selectListCache = nullptr;
}

SQLSelectParser::SQLSelectParser(Lexer_ptr theLexer)
    : super(theLexer)
{
  // LOG_INFO << ", in SQLSelectParser::SQLSelectParser, constructor step 2" << std::endl;
  // super(lexer);
  selectListCache = nullptr;
}

SQLSelectParser::SQLSelectParser(SQLExprParser_ptr theExprParser)
    : super(theExprParser->getLexer()), exprParser(theExprParser)
{
  // LOG_INFO << ", in SQLSelectParser::SQLSelectParser, constructor step 3" << std::endl;
  // super(exprParser.getLexer());
  // exprParser = theExprParser;
  LOG_INFO << ", in SQLSelectParser::SQLSelectParser token name:" << lexer->token()->getName() << std::endl;
  selectListCache = nullptr;
}

SQLSelectParser::SQLSelectParser(SQLExprParser_ptr exprParser, SQLSelectListCache_ptr selectListCache_)
    : SQLParser(exprParser->getLexer(), exprParser->getDbType()),
      exprParser(exprParser),
      selectListCache(selectListCache_)

{
  LOG_INFO << "in SQLSelectParser";
  selectListCache = nullptr;
}

SQLSelectParser::~SQLSelectParser()
{
  // LOG_INFO << ", in SQLSelectParser::~SQLSelectParser, destructor step 1" << std::endl;
}
SQLSelect_ptr SQLSelectParser::select()
{
  LOG_INFO << "in select";
  SQLSelect_ptr select = SQLSelect_ptr(new SQLSelect());

  LOG_INFO << "lexer->token_->name->c_str():" << lexer->token_->name->c_str();
  if (lexer->token_->name->c_str() == Token::WITH.name->c_str())
  {
    SQLWithSubqueryClause_ptr with = this->parseWith();
    select->setWithSubQuery(with);
  }

  SQLSelectQuery_ptr query_ = query(select, BOOL::TRUE);
  select->setQuery(query_);

  SQLOrderBy_ptr orderBy = this->parseOrderBy();

  if (instanceof <SQLSelectQuery, SQLSelectQueryBlock>(query_))
  {
    SQLSelectQueryBlock_ptr queryBlock = std::dynamic_pointer_cast<SQLSelectQueryBlock>(query_);

    if (queryBlock->getOrderBy() == nullptr)
    {
      queryBlock->setOrderBy(orderBy);
      if (lexer->token_->name->c_str() == Token::LIMIT.name->c_str())
      {
        SQLLimit_ptr limit = this->exprParser->parseLimit();
        queryBlock->setLimit(limit);
      }
    }
    else
    {
      select->setOrderBy(orderBy);
      if (lexer->token_->name->c_str() == Token::LIMIT.name->c_str())
      {
        SQLLimit_ptr limit = this->exprParser->parseLimit();
        select->setLimit(limit);
      }
    }

    if (orderBy != nullptr)
    {
      parseFetchClause(queryBlock);
    }
  }
  else
  {
    select->setOrderBy(orderBy);
  }

  if (lexer->token_->name->c_str() == Token::LIMIT.name->c_str())
  {
    SQLLimit_ptr limit = this->exprParser->parseLimit();
    select->setLimit(limit);
  }

  while (lexer->token_->name->c_str() == Token::HINT.name->c_str())
  {
    this->exprParser->parseHints(select->getHints());
  }

  return select;
}

std::shared_ptr<SQLUnionQuery> SQLSelectParser::createSQLUnionQuery()
{
  return std::shared_ptr<SQLUnionQuery>(new SQLUnionQuery());
}

std::shared_ptr<SQLUnionQuery> SQLSelectParser::unionRest(std::shared_ptr<SQLUnionQuery> xunion)
{
  if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
  {
    SQLOrderBy_ptr orderBy = exprParser->parseOrderBy();
    xunion->setOrderBy(orderBy);
    return unionRest(xunion);
  }
  return xunion;
}

SQLSelectQuery_ptr SQLSelectParser::queryRest(SQLSelectQuery_ptr selectQuery)
{
  return queryRest(selectQuery, BOOL::TRUE);
}

SQLSelectQuery_ptr SQLSelectParser::queryRest(SQLSelectQuery_ptr selectQuery, BOOL_ptr acceptUnion)
{
  if (!acceptUnion)
  {
    return selectQuery;
  }

  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::queryRest, step 1" << std::endl;

  // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLSelectParser::queryRest, step 1.01 " <<   lexer->token() <<  " " << tokenStringList.at(lexer->token()->name->c_str() ) <<  ": "  <<  lexer->getStringVal()  <<  ", pos "  <<  lexer->getPos()<< std::endl;

  if (lexer->token()->name->c_str() == Token::UNION.name->c_str())
  {
    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::queryRest, step 1.1" << std::endl;
    lexer->nextToken();

    std::shared_ptr<SQLUnionQuery> xunion = std::shared_ptr<SQLUnionQuery>(createSQLUnionQuery());
    xunion->setLeft(selectQuery);

    if (lexer->token()->name->c_str() == Token::ALL.name->c_str())
    {
      xunion->setOperator(SQLUnionOperator::UNION_ALL);
      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::DISTINCT.name->c_str())
    {
      xunion->setOperator(SQLUnionOperator::DISTINCT);
      lexer->nextToken();
    }
    SQLSelectQuery_ptr right = this->query();
    xunion->setRight(right);

    return unionRest(xunion);
  }

  if (lexer->token()->name->c_str() == Token::EXCEPT.name->c_str())
  {
    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::queryRest, step 1.2" << std::endl;
    lexer->nextToken();

    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::queryRest, step 1.2.1 creating new SQLUnionQuery" << std::endl;
    std::shared_ptr<SQLUnionQuery> xunion = std::shared_ptr<SQLUnionQuery>(new SQLUnionQuery());
    xunion->setLeft(selectQuery);

    xunion->setOperator(SQLUnionOperator::EXCEPT);

    SQLSelectQuery_ptr right = this->query();
    xunion->setRight(right);

    return xunion;
  }

  if (lexer->token()->name->c_str() == Token::INTERSECT.name->c_str())
  {
    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::queryRest, step 1.2.2 creating new SQLUnionQuery" << std::endl;
    lexer->nextToken();

    std::shared_ptr<SQLUnionQuery> xunion = std::shared_ptr<SQLUnionQuery>(new SQLUnionQuery());
    xunion->setLeft(selectQuery);

    xunion->setOperator(SQLUnionOperator::INTERSECT);

    SQLSelectQuery_ptr right = this->query();
    xunion->setRight(right);

    return xunion;
  }

  if (lexer->token()->name->c_str() == Token::MINUS.name->c_str())
  {
    lexer->nextToken();

    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::queryRest, step 1.2.3 creating new SQLUnionQuery" << std::endl;
    std::shared_ptr<SQLUnionQuery> xunion = std::shared_ptr<SQLUnionQuery>(new SQLUnionQuery());
    xunion->setLeft(selectQuery);

    xunion->setOperator(SQLUnionOperator::MINUS);

    SQLSelectQuery_ptr right = this->query();
    xunion->setRight(right);

    return xunion;
  }
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::queryRest, step 2" << std::endl;

  return selectQuery;
}

SQLSelectQuery_ptr SQLSelectParser::query()
{
  LOG_INFO << "goto new SQLObject";
  SQLObject_ptr tmp = SQLObject_ptr(new SQLObject());
  LOG_INFO << "goto query";
  return query(tmp, BOOL::TRUE);
}

SQLSelectQuery_ptr SQLSelectParser::query(SQLObject_ptr parent)
{
  return query(parent, BOOL::TRUE);
}

SQLSelectQuery_ptr SQLSelectParser::query(SQLObject_ptr parent, BOOL_ptr acceptUnion)
{

  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 1" << std::endl;
  if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
  {
    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 1.1" << std::endl;
    lexer->nextToken();

    SQLSelectQuery_ptr select = query();
    accept(Token::RPAREN);

    return queryRest(select, acceptUnion);
  }
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 2" << std::endl;
  if (lexer->token()->name->c_str() == Token::VALUES.name->c_str())
  {
    return valuesQuery(acceptUnion);
  }

  SQLSelectQueryBlock_ptr queryBlock = SQLSelectQueryBlock_ptr(new SQLSelectQueryBlock(dbType));

  if (lexer->hasComment() && lexer->isKeepComments())
  {
    queryBlock->addBeforeComment(lexer->readAndResetComments());
  }
  accept(Token::SELECT);
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 3" << std::endl;

  if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
  {
    this->exprParser->parseHints(queryBlock->getHints());
  }

  if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
  {
    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 3.1" << std::endl;
    lexer->nextToken();
  }
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 4, creating new SQLSelectQueryBlock" << std::endl;

  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 5" << std::endl;
  if (DbType::informix.name->c_str() == dbType->name->c_str())
  {
    if (lexer->identifierEquals(FnvHash::Constants::SKIP))
    {
      lexer->nextToken();
      SQLExpr_ptr offset = this->exprParser->primary();
      queryBlock->setOffset(offset);
    }

    if (lexer->identifierEquals(FnvHash::Constants::FIRST))
    {
      lexer->nextToken();
      SQLExpr_ptr first = this->exprParser->primary();
      queryBlock->setFirst(first);
    }
  }

  if (lexer->token()->name->c_str() == Token::DISTINCT.name->c_str())
  {

    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 5.1" << std::endl;
    queryBlock->setDistionOption(SQLSetQuantifier::DISTINCT);
    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 5.2" << std::endl;
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::UNIQUE.name->c_str())
  {
    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 5.3" << std::endl;

    queryBlock->setDistionOption(SQLSetQuantifier::UNIQUE);
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::ALL.name->c_str())
  {
    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 5.4" << std::endl;

    queryBlock->setDistionOption(SQLSetQuantifier::ALL);
    lexer->nextToken();
  }
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 6" << std::endl;

  parseSelectList(queryBlock);
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 7" << std::endl;

  if (lexer->token()->name->c_str() == Token::INTO.name->c_str())
  {
    lexer->nextToken();

    SQLExpr_ptr expr = this->expr();
    if (lexer->token()->name->c_str() != Token::COMMA.name->c_str())
    {
      queryBlock->setInto(expr);
    }
  }

  parseFrom(queryBlock);
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 8" << std::endl;

  parseWhere(queryBlock);
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 9" << std::endl;
  // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLSelectParser::query, step 9.1 " <<   lexer->token() <<  " " << tokenStringList.at(lexer->token()->name->c_str() ) <<  ": "  <<  lexer->getStringVal()  <<  ", pos "  <<  lexer->getPos()<< std::endl;

  parseGroupBy(queryBlock);
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::query, step 10" << std::endl;
  // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLSelectParser::query, step 10.1 " <<   lexer->token() <<  " " << tokenStringList.at(lexer->token()->name->c_str() ) <<  ": "  <<  lexer->getStringVal()  <<  ", pos "  <<  lexer->getPos()<< std::endl;

  if (lexer->identifierEquals(FnvHash::Constants::WINDOW))
  {
    parseWindow(queryBlock);
  }

  LOG_INFO << __FUNCTION__ << ", in goto parseSortBy";
  parseSortBy(queryBlock);

  LOG_INFO << __FUNCTION__ << ", in goto parseFetchClause";
  parseFetchClause(queryBlock);

  LOG_INFO << __FUNCTION__ << ", token name:" << lexer->token()->getName();
  if (lexer->token()->name->c_str() == Token::FOR.name->c_str())
  {
    lexer->nextToken();
    accept(Token::UPDATE);

    queryBlock->setForUpdate(BOOL::TRUE);

    if (lexer->identifierEquals(FnvHash::Constants::NO_WAIT) || lexer->identifierEquals(FnvHash::Constants::NOWAIT))
    {
      lexer->nextToken();
      queryBlock->setNoWait(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::WAIT))
    {
      lexer->nextToken();
      SQLExpr_ptr waitTime = this->exprParser->primary();
      queryBlock->setWaitTime(waitTime);
    }
  }
  return queryRest(queryBlock);
}

void SQLSelectParser::withSubquery(SQLSelect_ptr theSelect)
{
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::withSubquery, step 1" << std::endl;
  if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
  {
    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::withSubquery, step 1.1" << std::endl;
    lexer->nextToken();

    SQLWithSubqueryClause *withQueryClause = new SQLWithSubqueryClause();

    if (lexer->token()->name->c_str() == Token::RECURSIVE.name->c_str() || identifierEquals("RECURSIVE"))
    {
      lexer->nextToken();
      withQueryClause->setRecursive(BOOL::TRUE);
    }

    // for (;;) {
    // 	SQLWithSubqueryClause_Entry *entry = new SQLWithSubqueryClause_Entry();

    // 	SQLIdentifierExpr* v = dynamic_cast<SQLIdentifierExpr *>(exprParser->getName());
    // 	entry->setName(v);

    // 	if (lexer->token()->name->c_str() == LPAREN) {
    // 		lexer->nextToken();
    // 		exprParser->getNames(entry->getColumns());
    // 		accept(RPAREN);
    // 	}

    // 	accept(AS);
    // 	accept(LPAREN);
    // 	entry->setSubQuery(select());
    // 	accept(RPAREN);

    // 	withQueryClause->getEntries().push_back(entry);

    // 	if (lexer->token()->name->c_str() == COMMA) {
    // 		lexer->nextToken();
    // 		continue;
    // 	}

    // 	break;
    // }

    // theSelect->setWithSubQuery(withQueryClause);
  }
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::withSubquery, step 2" << std::endl;
}

void SQLSelectParser::parseWhere(SQLSelectQueryBlock_ptr queryBlock)
{

  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseWhere, step 1" << std::endl;
  // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLSelectParser::parseWhere, step 1.01 " <<   lexer->token() <<  " " << tokenStringList.at(lexer->token()->name->c_str() ) <<  ": "  <<  lexer->getStringVal()  <<  ", pos "  <<  lexer->getPos()<< std::endl;
  if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
  {
    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseWhere, step 1.1" << std::endl;
    lexer->nextToken();

    queryBlock->setWhere(expr());
  }
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseWhere, step 2" << std::endl;
}

void SQLSelectParser::parseGroupBy(SQLSelectQueryBlock_ptr queryBlock)
{
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseGroupBy, step 1" << std::endl;
  if (lexer->token()->name->c_str() == Token::GROUP.name->c_str())
  {

    lexer->nextToken();
    accept(Token::BY);

    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseGroupBy, step 1.1, creating new SQLSelectGroupByClause" << std::endl;
    SQLSelectGroupByClause_ptr groupBy = SQLSelectGroupByClause_ptr(new SQLSelectGroupByClause());
    while (BOOL::TRUE)
    {

      groupBy->getItems()->push_back(expr());
      if (lexer->token()->name->c_str() != Token::COMMA.name->c_str())
      {
        break;
      }

      lexer->nextToken();
    }

    if (lexer->token()->name->c_str() == Token::HAVING.name->c_str())
    {
      lexer->nextToken();

      groupBy->setHaving(expr());
    }

    queryBlock->setGroupBy(groupBy);
  }
  else if (lexer->token()->name->c_str() == (Token::HAVING.name->c_str()))
  {
    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseGroupBy, step 1.2, creating new SQLSelectGroupByClause" << std::endl;
    lexer->nextToken();

    SQLSelectGroupByClause_ptr groupBy = SQLSelectGroupByClause_ptr(new SQLSelectGroupByClause());

    groupBy->setHaving(this->expr());
    queryBlock->setGroupBy(groupBy);
  }
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseGroupBy, step 3, creating new SQLSelectGroupByClause" << std::endl;
}

void SQLSelectParser::parseSelectList(SQLSelectQueryBlock_ptr queryBlock)
{

  LOG_INFO << __FUNCTION__ << ": in SQLSelectParser::parseSelectList, step 1";
  SQLSelectItem_list_ptr selectList = queryBlock->getSelectList();
  for (;;)
  {
    LOG_INFO << __FUNCTION__ << ": in SQLSelectParser::parseSelectList, step 2";
    LOG_INFO << __FUNCTION__ << ": token name:" << lexer->token()->getName()->c_str() << ",this->exprParser->getLexer()->token()->getName:" << this->exprParser->getLexer()->token()->getName()->c_str();
    SQLSelectItem_ptr selectItem = this->exprParser->parseSelectItem();
    LOG_INFO << __FUNCTION__ << ": in SQLSelectParser::parseSelectList, step 3";
    selectList->push_back(selectItem);
    LOG_INFO << __FUNCTION__ << ": in SQLSelectParser::parseSelectList, step 4, selectList.size:" << selectList->size() << ",queryBlock->getSelectList().size:" << queryBlock->getSelectList()->size();

    // if (lexer->token()->name->c_str() != Token::COMMA) {
    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseSelectList, step 5" << std::endl;
    // 	break;
    // }

    // lexer->nextToken();
    selectItem->setParent(queryBlock);

    if (!(lexer->token()->name->c_str() == Token::COMMA.name->c_str()))
    {
      break;
    }

    int line = lexer->line;
    lexer->nextToken();
    if (lexer->hasComment() && lexer->isKeepComments() &&
        lexer->getComments()->size() == 1)
    {
      auto it_getComments = lexer->getComments()->begin();
      std::advance(it_getComments, 0);
      if (StringUtils::startWith(make_string_ptr(encode_util::UnicodeToUTF8((*it_getComments)->c_str())), make_string_ptr("--")) &&
          lexer->line == line + 1)
      {
        selectItem->addAfterComment(lexer->readAndResetComments());
      }
    }
  }
}

SQLSelectItem_ptr SQLSelectParser::parseSelectItem()
{
  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseSelectItem, step 1 lexer->token():" << lexer->token()->getName() << std::endl;
  SQLExpr_ptr theExpr;
  if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
  {

    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseSelectItem, step 2, creating new SQLIdentifierExpr" << std::endl;
    string_ptr tmp_str = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    theExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp_str));
    SQLExpr_ptr tmp = theExpr;

    lexer->nextTokenComma();

    if (lexer->token()->name->c_str() != Token::COMMA.name->c_str())
    {
      LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseSelectItem, step 2.2, creating new SQLIdentifierExpr" << std::endl;
      theExpr = exprParser->primaryRest(theExpr);
      LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseSelectItem, step 2.3, creating new SQLIdentifierExpr" << std::endl;
      theExpr = exprParser->exprRest(theExpr);
    }
    // delete tmp;
  }
  else
  {
    LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseSelectItem, step 3" << std::endl;
    theExpr = expr();
  }
  string_ptr alias = as();

  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseSelectItem, step 4" << std::endl;
  return SQLSelectItem_ptr(new SQLSelectItem(theExpr, alias));
}

void SQLSelectParser::parseFrom(SQLSelectQueryBlock_ptr queryBlock)
{

  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseFrom, step 1" << std::endl;
  if (lexer->token()->name->c_str() != Token::FROM.name->c_str())
  {
    return;
  }

  lexer->nextToken();

  queryBlock->setFrom(parseTableSource());

  LOG_INFO << __FUNCTION__ << ", in SQLSelectParser::parseFrom, step 2" << std::endl;
}

SQLTableSource_ptr SQLSelectParser::parseTableSource()
{

  if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
  {

    lexer->nextToken();
    SQLTableSource_ptr tableSource;

    if (lexer->token()->name->c_str() == Token::SELECT.name->c_str() ||
        lexer->token()->name->c_str() == Token::WITH.name->c_str())
    {

      SQLSelect_ptr theSelect = select();
      accept(Token::RPAREN);
      queryRest(theSelect->getQuery());
      tableSource = SQLTableSource_ptr(new SQLSubqueryTableSource(theSelect));
    }
    else if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {

      tableSource = parseTableSource();
      accept(Token::RPAREN);
    }
    else
    {

      tableSource = parseTableSource();
      accept(Token::RPAREN);
    }

    return parseTableSourceRest(tableSource);
  }

  if (lexer->token()->name->c_str() == Token::SELECT.name->c_str())
  {
    throw new ParserException(make_string_ptr("TODO"));
  }

  SQLExprTableSource_ptr tableReference = SQLExprTableSource_ptr(new SQLExprTableSource());

  parseTableSourceQueryTableExpr(tableReference);

  return parseTableSourceRest(tableReference);
}

void SQLSelectParser::parseTableSourceQueryTableExpr(SQLExprTableSource_ptr tableReference)
{

  if (lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str() ||
      lexer->token()->name->c_str() == Token::IDENTIFIED.name->c_str() ||
      lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
  {

    tableReference->setExpr(exprParser->getName());
    return;
  }

  tableReference->setExpr(expr());
}

SQLTableSource_ptr SQLSelectParser::parseTableSourceRest(SQLTableSource_ptr tableSource)
{
  parseTableSourceSample(tableSource);

  if (lexer->hasComment() && lexer->isKeepComments() && !(instanceof <SQLTableSource, SQLSubqueryTableSource>(*tableSource)))
  {
    string_list_ptr tmp = std::make_shared<std::list<string_ptr>>();
    for (auto it : *lexer->readAndResetComments())
    {
      tmp->push_back(make_string_ptr(encode_util::UnicodeToUTF8(*it)));
    }
    tableSource->addAfterComment(tmp);
  }

  if (tableSource->getAlias() == nullptr || tableSource->getAlias()->length() == 0)
  {
    Token_ptr token = lexer->token();
    long hash;

    if (*token == Token::LEFT ||
        *token == Token::RIGHT ||
        *token == Token::FULL)
    {
      Lexer_SavePoint_ptr mark = lexer->mark();
      string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::OUTER.name->c_str() ||
          lexer->token()->name->c_str() == Token::JOIN.name->c_str() ||
          lexer->identifierEquals(FnvHash::Constants::ANTI) ||
          lexer->identifierEquals(FnvHash::Constants::SEMI))
      {
        lexer->reset(mark);
      }
      else
      {
        tableSource->setAlias(strVal);
      }
    }

    else if (*token == Token::OUTER)
    {
    }
    else
    {
      if (identifierEquals("PIVOT") || identifierEquals("UNPIVOT"))
      {
        parsePivot(tableSource);
      }
      else if (!(*token == Token::IDENTIFIER &&
                 ((hash = lexer->hashLCase()) == FnvHash::Constants::STRAIGHT_JOIN ||
                  hash == FnvHash::Constants::CROSS)))
      {
        BOOL_ptr must = BOOL::FALSE;
        if (lexer->token()->name->c_str() == Token::AS.name->c_str())
        {
          lexer->nextToken();
          must = BOOL::TRUE;
        }
        string_ptr alias = tableAlias(must);
        if (alias != nullptr)
        {
          if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::IgnoreNameQuotes))) &&
              alias->length() > 1)
          {
            alias = StringUtils::removeNameQuotes(alias);
          }
          tableSource->setAlias(alias);

          if ((instanceof <SQLTableSource, SQLValuesTableSource>(tableSource)) &&
              (std::dynamic_pointer_cast<SQLValuesTableSource>(tableSource))->getColumns()->empty())
          {
            SQLValuesTableSource_ptr values = std::dynamic_pointer_cast<SQLValuesTableSource>(tableSource);
            accept(Token::LPAREN);
            this->exprParser->names(values->getColumns(), values);
            accept(Token::RPAREN);
          }
          else if (instanceof <SQLTableSource, SQLSubqueryTableSource>(*tableSource))
          {
            SQLSubqueryTableSource_ptr subQuery = std::dynamic_pointer_cast<SQLSubqueryTableSource>(tableSource);
            if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
            {
              lexer->nextToken();
              this->exprParser->names(subQuery->getColumns(), subQuery);
              accept(Token::RPAREN);
            }
          }
          else if (instanceof <SQLTableSource, SQLUnionQueryTableSource>(*tableSource))
          {
            SQLUnionQueryTableSource_ptr union_ = std::dynamic_pointer_cast<SQLUnionQueryTableSource>(tableSource);
            if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
            {
              lexer->nextToken();
              this->exprParser->names(union_->getColumns(), union_);
              accept(Token::RPAREN);
            }
          }
          else if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str() &&
                   instanceof <SQLTableSource, SQLExprTableSource>(*tableSource) &&
                                  ((instanceof <SQLExpr, SQLVariantRefExpr>(*(std::dynamic_pointer_cast<SQLExprTableSource>(tableSource)->getExpr()))) ||
                                   (instanceof <SQLExpr, SQLIdentifierExpr>(*(std::dynamic_pointer_cast<SQLExprTableSource>(tableSource)->getExpr())))))
          {
            lexer->nextToken();
            SQLExprTableSource_ptr exprTableSource = std::dynamic_pointer_cast<SQLExprTableSource>(tableSource);
            this->exprParser->names(exprTableSource->getColumns(), exprTableSource);
            accept(Token::RPAREN);
          }

          if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
          {
            return tableSource;
          }

          return parseTableSourceRest(tableSource);
        }
      }
    }
  }

  SQLJoinTableSource_JoinType_ptr joinType = nullptr;

  bool natural = lexer->identifierEquals(FnvHash::Constants::NATURAL);
  if (natural)
  {
    lexer->nextToken();
  }

  BOOL_ptr asof = BOOL::FALSE;
  if (lexer->identifierEquals(FnvHash::Constants::ASOF) && *dbType == DbType::clickhouse)
  {
    lexer->nextToken();
    asof = BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::OUTER.name->c_str())
  {
    Lexer_SavePoint_ptr mark = lexer->mark();
    string_ptr str = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    lexer->nextToken();
    if (tableSource->getAlias() == nullptr &&
        !lexer->identifierEquals(FnvHash::Constants::APPLY))
    {
      tableSource->setAlias(str);
    }
    else
    {
      lexer->reset(mark);
    }
  }

  BOOL_ptr global = BOOL::FALSE;
  if (*dbType == DbType::clickhouse)
  {
    if (lexer->token()->name->c_str() == Token::GLOBAL.name->c_str())
    {
      lexer->nextToken();
      global = BOOL::TRUE;
    }
  }

  if (lexer->token()->name->c_str() == Token::LEFT.name->c_str())
  {
    lexer->nextToken();

    if (lexer->identifierEquals(FnvHash::Constants::SEMI))
    {
      lexer->nextToken();
      joinType = SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::LEFT_SEMI_JOIN));
    }
    else if (lexer->identifierEquals(FnvHash::Constants::ANTI))
    {
      lexer->nextToken();
      joinType = SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::LEFT_ANTI_JOIN));
    }
    else if (lexer->token()->name->c_str() == Token::OUTER.name->c_str())
    {
      lexer->nextToken();
      joinType = SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::LEFT_OUTER_JOIN));
    }
    else
    {
      joinType = SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::LEFT_OUTER_JOIN));
    }

    if (*dbType == DbType::odps &&
        lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str() &&
        StringUtils::startWith(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())), make_string_ptr("join@")))
    {
      lexer->stringVal_ = lexer->stringVal()->substr(5);
      goto out1;
    }

    accept(Token::JOIN);
  }
  else if (lexer->token()->name->c_str() == Token::RIGHT.name->c_str())
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::OUTER.name->c_str())
    {
      lexer->nextToken();
    }
    accept(Token::JOIN);
    joinType = SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::RIGHT_OUTER_JOIN));
  }
  else if (lexer->token()->name->c_str() == Token::FULL.name->c_str())
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::OUTER.name->c_str())
    {
      lexer->nextToken();
    }
    accept(Token::JOIN);
    joinType = SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::FULL_OUTER_JOIN));
  }
  else if (lexer->token()->name->c_str() == Token::INNER.name->c_str())
  {
    lexer->nextToken();
    accept(Token::JOIN);
    joinType = SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::INNER_JOIN));
  }
  else if (lexer->token()->name->c_str() == Token::JOIN.name->c_str())
  {
    lexer->nextToken();
    joinType = natural ? SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::NATURAL_JOIN)) : SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::JOIN));
  }
  else if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
  {
    lexer->nextToken();
    joinType = SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::COMMA));
  }
  else if (lexer->token()->name->c_str() == Token::OUTER.name->c_str())
  {
    lexer->nextToken();
    if (lexer->identifierEquals(FnvHash::Constants::APPLY))
    {
      lexer->nextToken();
      joinType = SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::OUTER_APPLY));
    }
  }
  else if (lexer->token()->name->c_str() == Token::STRAIGHT_JOIN.name->c_str() ||
           lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
  {
    long hash = lexer->hashLCase();
    if (hash == FnvHash::Constants::STRAIGHT_JOIN)
    {
      lexer->nextToken();
      joinType = SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::STRAIGHT_JOIN));
    }
    else if (hash == FnvHash::Constants::STRAIGHT)
    {
      lexer->nextToken();
      accept(Token::JOIN);
      joinType = SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::STRAIGHT_JOIN));
    }
    else if (hash == FnvHash::Constants::CROSS)
    {
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::JOIN.name->c_str())
      {
        lexer->nextToken();
        joinType = natural ? SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::NATURAL_CROSS_JOIN)) : SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::CROSS_JOIN));
      }
      else if (lexer->identifierEquals(FnvHash::Constants::APPLY))
      {
        lexer->nextToken();
        joinType = SQLJoinTableSource_JoinType_ptr(new SQLJoinTableSource_JoinType(&SQLJoinTableSource_JoinType::CROSS_APPLY));
      }
    }
  }

out1:

  if (joinType != nullptr)
  {
    SQLJoinTableSource_ptr join = SQLJoinTableSource_ptr(new SQLJoinTableSource());
    join->setLeft(tableSource);
    join->setJoinType(joinType);
    join->setGlobal(global);
    if (asof)
    {
      join->setAsof(BOOL::TRUE);
    }

    BOOL_ptr isBrace = BOOL::FALSE;
    if (SQLJoinTableSource_JoinType::COMMA == *joinType)
    {
      if (lexer->token()->name->c_str() == Token::LBRACE.name->c_str())
      {
        lexer->nextToken();
        acceptIdentifier("OJ");
        isBrace = BOOL::TRUE;
      }
    }

    SQLTableSource_ptr rightTableSource = nullptr;
    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::SELECT.name->c_str() ||
          (lexer->token()->name->c_str() == Token::FROM.name->c_str() &&
           (*dbType == DbType::odps ||
            *dbType == DbType::hive)))
      {
        SQLSelect_ptr select = this->select();
        rightTableSource = SQLSubqueryTableSource_ptr(new SQLSubqueryTableSource(select));
      }
      else
      {
        rightTableSource = this->parseTableSource();
      }

      if (lexer->token()->name->c_str() == Token::UNION.name->c_str() ||
          lexer->token()->name->c_str() == Token::EXCEPT.name->c_str() ||
          lexer->token()->name->c_str() == Token::MINUS.name->c_str() ||
          lexer->token()->name->c_str() == Token::INTERSECT.name->c_str())
      {
        if (instanceof <SQLTableSource, SQLSubqueryTableSource>(rightTableSource))
        {
          SQLSelect_ptr select = (std::dynamic_pointer_cast<SQLSubqueryTableSource>(rightTableSource))->getSelect();
          SQLSelectQuery_ptr query = queryRest(select->getQuery(), BOOL::TRUE);
          select->setQuery(query);
        }
        else if (instanceof <SQLTableSource, SQLUnionQueryTableSource>(rightTableSource))
        {
          SQLUnionQueryTableSource_ptr unionTableSrc = std::dynamic_pointer_cast<SQLUnionQueryTableSource>(rightTableSource);
          unionTableSrc->setUnion(std::dynamic_pointer_cast<SQLUnionQuery>(queryRest(unionTableSrc->getUnion())));
        }
      }

      accept(Token::RPAREN);

      if (instanceof <SQLTableSource, SQLValuesTableSource>(rightTableSource) &&
                         (lexer->token()->name->c_str() == Token::AS.name->c_str() ||
                          lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) &&
                         rightTableSource->getAlias() == nullptr &&
                         (std::dynamic_pointer_cast<SQLValuesTableSource>(rightTableSource))->getColumns()->empty())
      {
        if (lexer->token()->name->c_str() == Token::AS.name->c_str())
        {
          lexer->nextToken();
        }
        rightTableSource->setAlias(tableAlias(BOOL::TRUE));

        if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
        {
          lexer->nextToken();
          this->exprParser->names((std::dynamic_pointer_cast<SQLValuesTableSource>(rightTableSource))->getColumns(), rightTableSource);
          accept(Token::RPAREN);
        }
      }
    }
    else if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
    {
      HiveCreateTableParser_ptr createTableParser = HiveCreateTableParser_ptr(new HiveCreateTableParser(lexer));
      HiveCreateTableStatement_ptr stmt = std::dynamic_pointer_cast<HiveCreateTableStatement>(createTableParser->parseCreateTable(BOOL::FALSE));
      rightTableSource = SQLAdhocTableSource_ptr(new SQLAdhocTableSource(stmt));
      primaryTableSourceRest(rightTableSource);
    }
    else
    {
      if (lexer->identifierEquals(FnvHash::Constants::UNNEST))
      {
        Lexer_SavePoint_ptr mark = lexer->mark();
        lexer->nextToken();

        if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
        {
          lexer->nextToken();
          SQLUnnestTableSource_ptr unnest = SQLUnnestTableSource_ptr(new SQLUnnestTableSource());
          this->exprParser->exprList(unnest->getItems(), unnest);
          accept(Token::RPAREN);

          if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
          {
            lexer->nextToken();
            acceptIdentifier("ORDINALITY");
            unnest->setOrdinality(BOOL::TRUE);
          }

          string_ptr alias = this->tableAlias();
          unnest->setAlias(alias);

          if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
          {
            lexer->nextToken();
            this->exprParser->names(unnest->getColumns(), unnest);
            accept(Token::RPAREN);
          }

          SQLTableSource_ptr tableSrc = parseTableSourceRest(unnest);
          rightTableSource = tableSrc;
        }
        else
        {
          lexer->reset(mark);
        }
      }
      else if (lexer->token()->name->c_str() == Token::VALUES.name->c_str())
      {
        rightTableSource = this->parseValues();
      }

      if (rightTableSource == nullptr)
      {
        bool aliasToken = lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str();
        SQLExpr_ptr expr;
        if (lexer->token()->name->c_str() == Token::ALL.name->c_str())
        {
          expr = this->exprParser->name();
        }
        else
        {
          expr = this->expr();
        }

        if (aliasToken && instanceof <SQLExpr, SQLCharExpr>(*expr))
        {
          expr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr((std::dynamic_pointer_cast<SQLCharExpr>(expr))->getText()));
        }
        SQLExprTableSource_ptr exprTableSource = SQLExprTableSource_ptr(new SQLExprTableSource(expr));

        if (instanceof <SQLExpr, SQLMethodInvokeExpr>(*expr) && lexer->token()->name->c_str() == Token::AS.name->c_str())
        {
          lexer->nextToken();
          string_ptr alias = this->tableAlias(BOOL::TRUE);
          exprTableSource->setAlias(alias);

          if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
          {
            lexer->nextToken();

            this->exprParser->names(exprTableSource->getColumns(), exprTableSource);
            accept(Token::RPAREN);
          }
        }

        rightTableSource = exprTableSource;
      }
      rightTableSource = primaryTableSourceRest(rightTableSource);
    }

    if (lexer->token()->name->c_str() == Token::USING.name->c_str() || lexer->identifierEquals(FnvHash::Constants::USING))
    {
      Lexer_SavePoint_ptr savePoint = lexer->mark();
      lexer->nextToken();

      if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
      {
        lexer->nextToken();
        join->setRight(rightTableSource);
        this->exprParser->exprList(join->getUsing(), join);
        accept(Token::RPAREN);
      }
      else if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
      {
        lexer->reset(savePoint);
        join->setRight(rightTableSource);
        return join;
      }
      else
      {
        join->setAlias(this->tableAlias());
      }
    }
    else if (lexer->token()->name->c_str() == Token::STRAIGHT_JOIN.name->c_str() || lexer->identifierEquals(FnvHash::Constants::STRAIGHT_JOIN))
    {
      primaryTableSourceRest(rightTableSource);
    }
    else if (rightTableSource->getAlias() == nullptr && !(instanceof <SQLTableSource, SQLValuesTableSource>(rightTableSource)))
    {
      int line = lexer->line;
      string_ptr tableAlias;
      if (lexer->token()->name->c_str() == Token::AS.name->c_str())
      {
        lexer->nextToken();

        if (lexer->token()->name->c_str() != Token::ON.name->c_str())
        {
          tableAlias = this->tableAlias(BOOL::TRUE);
        }
        else
        {
          tableAlias = nullptr;
        }
      }
      else
      {
        tableAlias = this->tableAlias(BOOL::FALSE);
      }

      if (tableAlias != nullptr)
      {
        rightTableSource->setAlias(tableAlias);

        if (line + 1 == lexer->line && lexer->hasComment())
        {
          auto it_getComments = lexer->getComments()->begin();
          std::advance(it_getComments, 0);
          if (StringUtils::startWith(make_string_ptr(encode_util::UnicodeToUTF8((*it_getComments)->c_str())), make_string_ptr("--")))
          {
            string_list_ptr tmp = std::make_shared<std::list<string_ptr>>();
            for (auto it : *lexer->readAndResetComments())
            {
              tmp->push_back(make_string_ptr(encode_util::UnicodeToUTF8(*it)));
            }
            rightTableSource->addAfterComment(tmp);
          }
        }

        if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
        {
          if (instanceof <SQLTableSource, SQLSubqueryTableSource>(rightTableSource))
          {
            lexer->nextToken();
            SQLName_list_ptr columns = (std::dynamic_pointer_cast<SQLSubqueryTableSource>(rightTableSource))->getColumns();
            this->exprParser->names(columns, rightTableSource);
            accept(Token::RPAREN);
          }
          else if (instanceof <SQLTableSource, SQLExprTableSource>(rightTableSource) && instanceof <SQLExpr, SQLMethodInvokeExpr>((std::dynamic_pointer_cast<SQLExprTableSource>(rightTableSource))->getExpr()))
          {
            SQLName_list_ptr columns = (std::dynamic_pointer_cast<SQLExprTableSource>(rightTableSource))->getColumns();
            if (columns->empty())
            {
              lexer->nextToken();
              this->exprParser->names(columns, rightTableSource);
              accept(Token::RPAREN);
            }
          }
        }
      }

      rightTableSource = primaryTableSourceRest(rightTableSource);
    }

    if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
    {
      lexer->nextToken();
      accept(Token::LPAREN);

      for (;;)
      {
        SQLExpr_ptr hintExpr = this->expr();
        SQLExprHint_ptr hint = SQLExprHint_ptr(new SQLExprHint(hintExpr));
        hint->SQLObjectImpl::setParent(std::dynamic_pointer_cast<SQLObject>(tableSource));
        rightTableSource->getHints()->push_back(hint);
        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
        {
          lexer->nextToken();
          continue;
        }
        else
        {
          break;
        }
      }

      accept(Token::RPAREN);
    }

    join->setRight(rightTableSource);

    if (!natural)
    {
      if (!StringUtils::isEmpty(tableSource->getAlias()) &&
          tableSource->aliasHashCode64() == FnvHash::Constants::NATURAL &&
          DbType::mysql == *dbType)
      {
        tableSource->setAlias(nullptr);
        natural = true;
      }
    }
    join->setNatural(natural ? BOOL::TRUE : BOOL::FALSE);

    if (lexer->token()->name->c_str() == Token::ON.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr joinOn = expr();
      join->setCondition(joinOn);

      while (lexer->token()->name->c_str() == Token::ON.name->c_str())
      {
        lexer->nextToken();

        SQLExpr_ptr joinOn2 = expr();
        join->addCondition(joinOn2);
      }

      if (*dbType == DbType::odps &&
          lexer->identifierEquals(FnvHash::Constants::USING))
      {
        SQLJoinTableSource_UDJ_ptr udj = SQLJoinTableSource_UDJ_ptr(new SQLJoinTableSource_UDJ());
        lexer->nextToken();
        udj->setFunction(this->exprParser->name());
        accept(Token::LPAREN);
        this->exprParser->exprList(udj->getArguments(), udj);
        accept(Token::RPAREN);

        if (lexer->token()->name->c_str() != Token::AS.name->c_str())
        {
          udj->setAlias(alias());
        }

        accept(Token::AS);
        accept(Token::LPAREN);
        this->exprParser->names(udj->getColumns(), udj);
        accept(Token::RPAREN);

        if (lexer->identifierEquals(FnvHash::Constants::SORT))
        {
          lexer->nextToken();
          accept(Token::BY);
          this->exprParser->orderBy(udj->getSortBy(), udj);
        }

        if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
        {
          lexer->nextToken();
          acceptIdentifier("UDFPROPERTIES");
          this->exprParser->parseAssignItem(udj->getProperties(), udj);
        }

        join->setUdj(udj);
      }
    }
    else if (lexer->token()->name->c_str() == Token::USING.name->c_str() || lexer->identifierEquals(FnvHash::Constants::USING))
    {
      Lexer_SavePoint_ptr savePoint = lexer->mark();
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
      {
        lexer->nextToken();
        this->exprParser->exprList(join->getUsing(), join);
        accept(Token::RPAREN);
      }
      else
      {
        lexer->reset(savePoint);
      }
    }

    SQLTableSource_ptr tableSourceReturn = parseTableSourceRest(join);

    if (isBrace)
    {
      accept(Token::RBRACE);
    }

    return parseTableSourceRest(tableSourceReturn);
  }

  if ((tableSource->aliasHashCode64() == FnvHash::Constants::LATERAL ||
       lexer->token()->name->c_str() == Token::LATERAL.name->c_str()) &&
      lexer->token()->name->c_str() == Token::VIEW.name->c_str())
  {
    return parseLateralView(tableSource);
  }

  if (lexer->identifierEquals(FnvHash::Constants::LATERAL) || lexer->token()->name->c_str() == Token::LATERAL.name->c_str())
  {
    lexer->nextToken();
    return parseLateralView(tableSource);
  }

  return tableSource;
}
// {

//   if ((tableSource->getAlias() == nullptr) || (tableSource->getAlias()->length() == 0))
//   {
//     if (lexer->token()->name->c_str() != Token::LEFT && lexer->token()->name->c_str() != Token::RIGHT && lexer->token()->name->c_str() != Token::FULL)
//     {

//       string_ptr alias = as();
//       if (alias != make_string_ptr(""))
//       {

//         tableSource->setAlias(alias);
//         return parseTableSourceRest(tableSource);
//       }
//     }
//   }

//   JoinType joinType = JoinType::LEFT_OUTER_JOIN;
//   BOOL_ptr xIsNull = BOOL::TRUE;

//   if (lexer->token()->name->c_str() == Token::LEFT)
//   {
//     lexer->nextToken();
//     if (lexer->token()->name->c_str() == Token::OUTER)
//     {
//       lexer->nextToken();
//     }

//     accept(Token::JOIN);
//     joinType = JoinType::LEFT_OUTER_JOIN;
//     xIsNull = BOOL::FALSE;
//   }
//   else if (lexer->token()->name->c_str() == Token::RIGHT)
//   {

//     lexer->nextToken();

//     if (lexer->token()->name->c_str() == Token::OUTER)
//     {
//       lexer->nextToken();
//     }

//     accept(Token::JOIN);
//     joinType = JoinType::RIGHT_OUTER_JOIN;
//     xIsNull = BOOL::FALSE;
//   }
//   else if (lexer->token()->name->c_str() == Token::FULL)
//   {

//     lexer->nextToken();
//     if (lexer->token()->name->c_str() == Token::OUTER)
//     {
//       lexer->nextToken();
//     }
//     accept(Token::JOIN);
//     joinType = JoinType::FULL_OUTER_JOIN;
//     xIsNull = BOOL::FALSE;
//   }
//   else if (lexer->token()->name->c_str() == Token::INNER)
//   {

//     lexer->nextToken();
//     accept(Token::JOIN);
//     joinType = JoinType::INNER_JOIN;
//     xIsNull = BOOL::FALSE;
//   }
//   else if (lexer->token()->name->c_str() == Token::JOIN)
//   {

//     lexer->nextToken();
//     joinType = JoinType::JOIN;
//     xIsNull = BOOL::FALSE;
//   }
//   else if (lexer->token()->name->c_str() == Token::COMMA)
//   {

//     lexer->nextToken();
//     joinType = JoinType::COMMA;
//     xIsNull = BOOL::FALSE;
//   }
//   else if (identifierEquals("STRAIGHT_JOIN"))
//   {

//     lexer->nextToken();
//     joinType = JoinType::STRAIGHT_JOIN;
//     xIsNull = BOOL::FALSE;
//   }
//   else if (identifierEquals("CROSS"))
//   {

//     lexer->nextToken();
//     accept(Token::JOIN);
//     joinType = JoinType::CROSS_JOIN;
//     xIsNull = BOOL::FALSE;
//   }

//   // if (joinType != NULL) {
//   if (!xIsNull)
//   {
//     SQLJoinTableSource_ptr join = SQLJoinTableSource_ptr(new SQLJoinTableSource());
//     join->setLeft(tableSource);
//     join->setJoinType(joinType);
//     join->setRight(parseTableSource());

//     if (lexer->token()->name->c_str() == Token::ON)
//     {

//       lexer->nextToken();
//       join->setCondition(expr());
//     }
//     else if (identifierEquals("USING"))
//     {

//       lexer->nextToken();
//       if (lexer->token()->name->c_str() == Token::LPAREN)
//       {
//         lexer->nextToken();
//         exprParser->exprList(join->getUsing());
//         accept(Token::RPAREN);
//       }
//       else
//       {
//         join->getUsing()->push_back(expr());
//       }
//     }

//     return parseTableSourceRest(join);
//   }

//   return tableSource;
// }

SQLExpr_ptr SQLSelectParser::expr()
{
  return exprParser->getExpr();
}

SQLOrderBy_ptr SQLSelectParser::parseOrderBy()
{
  return exprParser->parseOrderBy();
}

void SQLSelectParser::acceptKeyword(string_ptr ident)
{

  if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str() &&
      StringUtils::iequals(ident->c_str(), encode_util::UnicodeToUTF8(lexer->stringVal()->c_str())))
  {
    lexer->nextToken();
  }
  else
  {
    setErrorEndPos(lexer->pos());

    std::stringstream stream;
    // stream << "syntax error, expect " <<  ident  <<  ", actual "  <<  tokenStringList.at(lexer->token()->name->c_str());
    stream << "syntax error, expect " << ident << ", actual ";

    throw new ParserException(make_string_ptr(stream.str()));
  }
}

SQLSelectQuery_ptr SQLSelectParser::valuesQuery(BOOL_ptr acceptUnion)
{
  lexer->nextToken();
  std::shared_ptr<SQLValuesQuery> valuesQuery = std::shared_ptr<SQLValuesQuery>(new SQLValuesQuery());

  for (;;)
  {
    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();
      SQLListExpr_ptr listExpr = SQLListExpr_ptr(new SQLListExpr());
      this->exprParser->exprList(listExpr->getItems(), listExpr);
      accept(Token::RPAREN);
      valuesQuery->addValue(listExpr);
    }
    else
    {
      this->exprParser->exprList(valuesQuery->getValues(), valuesQuery);
    }

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    else
    {
      break;
    }
  }

  return queryRest(valuesQuery, acceptUnion);
}

void SQLSelectParser::parseWindow(SQLSelectQueryBlock_ptr queryBlock)
{
  if (!(lexer->identifierEquals(FnvHash::Constants::WINDOW) || lexer->token()->name->c_str() == Token::WINDOW.name->c_str()))
  {
    return;
  }

  lexer->nextToken();

  for (;;)
  {
    SQLName_ptr name = this->exprParser->name();
    accept(Token::AS);
    SQLOver_ptr over = SQLOver_ptr(new SQLOver());
    this->exprParser->over(over);
    queryBlock->addWindow(SQLWindow_ptr(new SQLWindow(name, over)));

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }

    break;
  }
}

void SQLSelectParser::parseSortBy(SQLSelectQueryBlock_ptr queryBlock)
{
  LOG_INFO << __FUNCTION__ << ", token name:" << lexer->token()->getName();
  if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
  {
    LOG_INFO << __FUNCTION__ << ":";
    SQLOrderBy_ptr orderBy = parseOrderBy();

    queryBlock->setOrderBy(orderBy);
  }

  if (lexer->identifierEquals(FnvHash::Constants::DISTRIBUTE))
  {
    LOG_INFO << __FUNCTION__ << ":";
    lexer->nextToken();
    accept(Token::BY);

    for (;;)
    {
      LOG_INFO << __FUNCTION__ << ":";
      SQLSelectOrderByItem_ptr distributeByItem = this->exprParser->parseSelectOrderByItem();
      queryBlock->addDistributeBy(distributeByItem);

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        LOG_INFO << __FUNCTION__ << ":";
        lexer->nextToken();
      }
      else
      {
        LOG_INFO << __FUNCTION__ << ":";
        break;
      }
    }
  }

  if (lexer->identifierEquals(FnvHash::Constants::SORT))
  {
    LOG_INFO << __FUNCTION__ << ":";
    lexer->nextToken();
    accept(Token::BY);

    for (;;)
    {
      LOG_INFO << __FUNCTION__ << ":";
      SQLSelectOrderByItem_ptr sortByItem = this->exprParser->parseSelectOrderByItem();
      queryBlock->addSortBy(sortByItem);

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        LOG_INFO << __FUNCTION__ << ":";
        lexer->nextToken();
      }
      else
      {
        LOG_INFO << __FUNCTION__ << ":";
        break;
      }
    }
  }

  if (lexer->identifierEquals(FnvHash::Constants::CLUSTER))
  {
    LOG_INFO << __FUNCTION__ << ":";
    lexer->nextToken();
    accept(Token::BY);

    for (;;)
    {
      LOG_INFO << __FUNCTION__ << ":";
      SQLSelectOrderByItem_ptr clusterByItem = this->exprParser->parseSelectOrderByItem();
      queryBlock->addClusterBy(clusterByItem);

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        LOG_INFO << __FUNCTION__ << ":";
        lexer->nextToken();
      }
      else
      {
        LOG_INFO << __FUNCTION__ << ":";
        break;
      }
    }
  }
}

void SQLSelectParser::parseFetchClause(SQLSelectQueryBlock_ptr queryBlock)
{
  if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
  {
    SQLLimit_ptr limit = this->exprParser->parseLimit();
    queryBlock->setLimit(limit);
    return;
  }

  if (lexer->identifierEquals(FnvHash::Constants::OFFSET) ||
      lexer->token()->name->c_str() == Token::OFFSET.name->c_str())
  {
    lexer->nextToken();
    SQLExpr_ptr offset = this->exprParser->getExpr();
    queryBlock->setOffset(offset);
    if (lexer->identifierEquals(FnvHash::Constants::ROW) ||
        lexer->identifierEquals(FnvHash::Constants::ROWS))
    {
      lexer->nextToken();
    }
  }

  if (lexer->token()->name->c_str() == Token::FETCH.name->c_str())
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::FIRST.name->c_str() ||
        lexer->token()->name->c_str() == Token::NEXT.name->c_str() ||
        lexer->identifierEquals(FnvHash::Constants::NEXT))
    {
      lexer->nextToken();
    }
    else
    {
      acceptIdentifier("FIRST");
    }
    SQLExpr_ptr first = this->exprParser->primary();
    queryBlock->setFirst(first);
    if (lexer->identifierEquals(FnvHash::Constants::ROW) || lexer->identifierEquals(FnvHash::Constants::ROWS))
    {
      lexer->nextToken();
    }

    if (lexer->token()->name->c_str() == Token::ONLY.name->c_str())
    {
      lexer->nextToken();
    }
    else
    {
      acceptIdentifier("ONLY");
    }
  }
}

void SQLSelectParser::parseHierachical(SQLSelectQueryBlock_ptr queryBlock)
{
  if (lexer->token()->name->c_str() == Token::CONNECT.name->c_str() ||
      lexer->identifierEquals(FnvHash::Constants::CONNECT))
  {
    lexer->nextToken();
    accept(Token::BY);

    if (lexer->token()->name->c_str() == Token::PRIOR.name->c_str() ||
        lexer->identifierEquals(FnvHash::Constants::PRIOR))
    {
      lexer->nextToken();
      queryBlock->setPrior(BOOL::TRUE);
    }

    if (lexer->identifierEquals(FnvHash::Constants::NOCYCLE))
    {
      queryBlock->setNoCycle(BOOL::TRUE);
      lexer->nextToken();

      if (lexer->token()->name->c_str() == Token::PRIOR.name->c_str())
      {
        lexer->nextToken();
        queryBlock->setPrior(BOOL::TRUE);
      }
    }
    queryBlock->setConnectBy(this->exprParser->getExpr());
  }

  if (lexer->token()->name->c_str() == Token::START.name->c_str() ||
      lexer->identifierEquals(FnvHash::Constants::START))
  {
    lexer->nextToken();
    accept(Token::WITH);

    queryBlock->setStartWith(this->exprParser->getExpr());
  }

  if (lexer->token()->name->c_str() == Token::CONNECT.name->c_str() ||
      lexer->identifierEquals(FnvHash::Constants::CONNECT))
  {
    lexer->nextToken();
    accept(Token::BY);

    if (lexer->token()->name->c_str() == Token::PRIOR.name->c_str() || lexer->identifierEquals(FnvHash::Constants::PRIOR))
    {
      lexer->nextToken();
      queryBlock->setPrior(BOOL::TRUE);
    }

    if (lexer->identifierEquals(FnvHash::Constants::NOCYCLE))
    {
      queryBlock->setNoCycle(BOOL::TRUE);
      lexer->nextToken();

      if (lexer->token()->name->c_str() == Token::PRIOR.name->c_str() || lexer->identifierEquals(FnvHash::Constants::PRIOR))
      {
        lexer->nextToken();
        queryBlock->setPrior(BOOL::TRUE);
      }
    }
    queryBlock->setConnectBy(this->exprParser->getExpr());
  }
}

void SQLSelectParser::parseTableSourceSample(SQLTableSource_ptr tableSource)
{
}

void SQLSelectParser::parsePivot(SQLTableSource_ptr tableSource)
{
  SQLSelectItem_ptr item;
  if (lexer->identifierEquals(FnvHash::Constants::PIVOT))
  {
    lexer->nextToken();

    SQLPivot_ptr pivot = SQLPivot_ptr(new SQLPivot());

    if (lexer->identifierEquals(L"XML"))
    {
      lexer->nextToken();
      pivot->setXml(BOOL::TRUE);
    }

    accept(Token::LPAREN);
    while (BOOL::TRUE)
    {
      item = SQLSelectItem_ptr(new SQLSelectItem());
      item->setExpr(this->exprParser->expr());
      item->setAlias(as());
      pivot->addItem(item);

      if (!(lexer->token()->name->c_str() == (Token::COMMA.name->c_str())))
      {
        break;
      }
      lexer->nextToken();
    }

    accept(Token::FOR);

    if (lexer->token()->name->c_str() == (Token::LPAREN.name->c_str()))
    {
      lexer->nextToken();
      while (BOOL::TRUE)
      {
        pivot->getPivotFor()->push_back(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())))));
        lexer->nextToken();

        if (!(lexer->token()->name->c_str() == (Token::COMMA.name->c_str())))
        {
          break;
        }
        lexer->nextToken();
      }

      accept(Token::RPAREN);
    }
    else
    {
      pivot->getPivotFor()->push_back(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())))));
      lexer->nextToken();
    }

    accept(Token::IN);
    accept(Token::LPAREN);
    //            if (lexer->token() == (Token::LPAREN)) {
    //                throw new ParserException("TODO. " + lexer->info());
    //            }

    if (lexer->token()->name->c_str() == (Token::SELECT.name->c_str()))
    {
      SQLExpr_ptr expr = this->exprParser->expr();
      item = SQLSelectItem_ptr(new SQLSelectItem());
      item->setExpr(expr);
      item->setParent(pivot);
      pivot->getPivotIn()->push_back(item);
    }
    else
    {
      for (;;)
      {
        item = SQLSelectItem_ptr(new SQLSelectItem());
        item->setExpr(this->exprParser->expr());
        item->setAlias(as());
        item->setParent(pivot);
        pivot->getPivotIn()->push_back(item);

        if (lexer->token()->name->c_str() != Token::COMMA.name->c_str())
        {
          break;
        }

        lexer->nextToken();
      }
    }

    accept(Token::RPAREN);

    accept(Token::RPAREN);

    tableSource->setPivot(pivot);
  }
  else if (lexer->identifierEquals(L"UNPIVOT"))
  {
    lexer->nextToken();

    SQLUnpivot_ptr unPivot = SQLUnpivot_ptr(new SQLUnpivot());
    if (lexer->identifierEquals(L"INCLUDE"))
    {
      lexer->nextToken();
      acceptIdentifier("NULLS");
      unPivot->setNullsIncludeType(SQLUnpivot_NullsIncludeType::INCLUDE_NULLS);
    }
    else if (lexer->identifierEquals(L"EXCLUDE"))
    {
      lexer->nextToken();
      acceptIdentifier("NULLS");
      unPivot->setNullsIncludeType(SQLUnpivot_NullsIncludeType::EXCLUDE_NULLS);
    }

    accept(Token::LPAREN);

    if (lexer->token()->name->c_str() == (Token::LPAREN.name->c_str()))
    {
      lexer->nextToken();
      this->exprParser->exprList(unPivot->getItems(), unPivot);
      accept(Token::RPAREN);
    }
    else
    {
      unPivot->addItem(this->exprParser->expr());
    }

    accept(Token::FOR);

    if (lexer->token()->name->c_str() == (Token::LPAREN.name->c_str()))
    {
      lexer->nextToken();
      while (BOOL::TRUE)
      {
        unPivot->getPivotFor()->push_back(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())))));
        lexer->nextToken();

        if (!(lexer->token()->name->c_str() == (Token::COMMA.name->c_str())))
        {
          break;
        }
        lexer->nextToken();
      }

      accept(Token::RPAREN);
    }
    else
    {
      unPivot->getPivotFor()->push_back(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())))));
      lexer->nextToken();
    }

    accept(Token::IN);
    accept(Token::LPAREN);
    if (lexer->token()->name->c_str() == (Token::LPAREN.name->c_str()))
    {
      throw new ParserException(make_string_ptr("TODO. " + encode_util::UnicodeToUTF8(lexer->info())));
    }

    if (lexer->token()->name->c_str() == (Token::SELECT.name->c_str()))
    {
      throw new ParserException(make_string_ptr("TODO. " + encode_util::UnicodeToUTF8(lexer->info())));
    }

    for (;;)
    {
      item = SQLSelectItem_ptr(new SQLSelectItem());
      item->setExpr(this->exprParser->expr());
      item->setAlias(as());
      unPivot->getPivotIn()->push_back(item);

      if (lexer->token()->name->c_str() != Token::COMMA.name->c_str())
      {
        break;
      }

      lexer->nextToken();
    }

    accept(Token::RPAREN);

    accept(Token::RPAREN);

    tableSource->setUnpivot(unPivot);
  }
}

void SQLSelectParser::parseTableSourceSampleHive(SQLTableSource_ptr tableSource)
{
  if (lexer->identifierEquals(FnvHash::Constants::TABLESAMPLE) && instanceof <SQLTableSource, SQLExprTableSource>(tableSource))
  {
    Lexer_SavePoint_ptr mark = lexer->mark();
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();

      SQLTableSampling_ptr sampling = SQLTableSampling_ptr(new SQLTableSampling());

      if (lexer->identifierEquals(FnvHash::Constants::BUCKET))
      {
        lexer->nextToken();
        SQLExpr_ptr bucket = this->exprParser->primary();
        sampling->setBucket(bucket);

        if (lexer->token()->name->c_str() == Token::OUT.name->c_str())
        {
          lexer->nextToken();
          accept(Token::OF);
          SQLExpr_ptr outOf = this->exprParser->primary();
          sampling->setOutOf(outOf);
        }

        if (lexer->token()->name->c_str() == Token::ON.name->c_str())
        {
          lexer->nextToken();
          SQLExpr_ptr on = this->exprParser->expr();
          sampling->setOn(on);
        }
      }

      if (lexer->token()->name->c_str() == Token::LITERAL_INT.name->c_str() || lexer->token()->name->c_str() == Token::LITERAL_FLOAT.name->c_str())
      {
        SQLExpr_ptr val = this->exprParser->primary();

        if (lexer->identifierEquals(FnvHash::Constants::ROWS))
        {
          lexer->nextToken();
          sampling->setRows(val);
        }
        else
        {
          acceptIdentifier("PERCENT");
          sampling->setPercent(val);
        }
      }

      if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
      {
        string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        char first = strVal->at(0);
        char last = strVal->at(strVal->length() - 1);
        if (last >= 'a' && last <= 'z')
        {
          last -= 32; // to upper
        }

        BOOL_ptr match = BOOL::FALSE;
        if ((first == '.' || (first >= '0' && first <= '9')))
        {
          switch (last)
          {
          case 'B':
          case 'K':
          case 'M':
          case 'G':
          case 'T':
          case 'P':
            match = BOOL::TRUE;
            break;
          default:
            break;
          }
        }
        SQLSizeExpr_ptr size = SQLSizeExpr_ptr(new SQLSizeExpr(make_string_ptr(strVal->substr(0, strVal->length() - 2)), last));
        sampling->setByteLength(size);
        lexer->nextToken();
      }

      SQLExprTableSource_ptr table = std::dynamic_pointer_cast<SQLExprTableSource>(tableSource);
      table->setSampling(sampling);

      accept(Token::RPAREN);
    }
    else
    {
      lexer->reset(mark);
    }
  }
}

SQLTableSource_ptr SQLSelectParser::primaryTableSourceRest(SQLTableSource_ptr tableSource)
{
  return tableSource;
}

SQLValuesTableSource_ptr SQLSelectParser::parseValues()
{
  accept(Token::VALUES);
  SQLValuesTableSource_ptr tableSource = SQLValuesTableSource_ptr(new SQLValuesTableSource());

  for (;;)
  {
    // compatible (VALUES 1,2,3) and (VALUES (1), (2), (3)) for ads
    BOOL_ptr isSingleValue = BOOL::TRUE;
    if (lexer->token()->name->c_str() == Token::ROW.name->c_str())
    {
      lexer->nextToken();
    }
    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      accept(Token::LPAREN);
      isSingleValue = BOOL::FALSE;
    }

    SQLListExpr_ptr listExpr = SQLListExpr_ptr(new SQLListExpr());

    if (isSingleValue)
    {
      SQLExpr_ptr expr_ = expr();
      expr_->setParent(listExpr);
      listExpr->getItems()->push_back(expr_);
    }
    else
    {
      this->exprParser->exprList(listExpr->getItems(), listExpr);
      accept(Token::RPAREN);
    }

    listExpr->setParent(tableSource);

    tableSource->getValues()->push_back(listExpr);

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    break;
  }

  string_ptr alias = this->tableAlias();
  if (alias != nullptr)
  {
    tableSource->setAlias(alias);
  }

  if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
  {
    lexer->nextToken();
    this->exprParser->names(tableSource->getColumns(), tableSource);
    accept(Token::RPAREN);
  }

  return tableSource;
}

SQLTableSource_ptr SQLSelectParser::parseLateralView(SQLTableSource_ptr tableSource)
{
  accept(Token::VIEW);
  if (tableSource != nullptr && StringUtils::equalsIgnoreCase(make_string_ptr("LATERAL"), (tableSource->getAlias())))
  {
    tableSource->setAlias(nullptr);
  }
  SQLLateralViewTableSource_ptr lateralViewTabSrc = SQLLateralViewTableSource_ptr(new SQLLateralViewTableSource());
  lateralViewTabSrc->setTableSource(tableSource);

  if (lexer->token()->name->c_str() == Token::OUTER.name->c_str())
  {
    lateralViewTabSrc->setOuter(BOOL::TRUE);
    lexer->nextToken();
  }

  SQLMethodInvokeExpr_ptr udtf = std::dynamic_pointer_cast<SQLMethodInvokeExpr>(this->exprParser->primary());
  lateralViewTabSrc->setMethod(udtf);

  string_ptr alias_;
  if (lexer->token()->name->c_str() == Token::AS.name->c_str())
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::AS.name->c_str())
    {
      lexer->nextToken();
    }

    alias_ = alias();
  }
  else
  {
    alias_ = as();
  }
  if (alias_ != nullptr)
  {
    lateralViewTabSrc->setAlias(alias_);
  }

  if (lexer->token()->name->c_str() == Token::AS.name->c_str())
  {
    parseLateralViewAs(lateralViewTabSrc);
  }

  if (lexer->token()->name->c_str() == Token::ON.name->c_str())
  {
    lexer->nextToken();
    lateralViewTabSrc->setOn(this->exprParser->expr());
  }

  return parseTableSourceRest(lateralViewTabSrc);
}

void SQLSelectParser::parseLateralViewAs(SQLLateralViewTableSource_ptr lateralViewTabSrc)
{
  accept(Token::AS);

  Lexer_SavePoint_ptr mark = nullptr;
  for (;;)
  {
    SQLName_ptr name;
    if (lexer->token()->name->c_str() == Token::XNULL.name->c_str())
    {
      name = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()))));
      lexer->nextToken();
    }
    else
    {
      name = this->exprParser->name();
      if (instanceof <SQLName, SQLPropertyExpr>(*name))
      {
        lexer->reset(mark);
        break;
      }
    }
    name->setParent(lateralViewTabSrc);
    lateralViewTabSrc->getColumns()->push_back(name);
    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      mark = lexer->mark();
      lexer->nextToken();
      continue;
    }
    break;
  }
}

SQLWithSubqueryClause_ptr SQLSelectParser::parseWith()
{
  SQLWithSubqueryClause_ptr withQueryClause = SQLWithSubqueryClause_ptr(new SQLWithSubqueryClause());
  if (lexer->hasComment() && lexer->isKeepComments())
  {
    withQueryClause->addBeforeComment(lexer->readAndResetComments());
  }

  accept(Token::WITH);

  if (lexer->token()->name->c_str() == Token::RECURSIVE.name->c_str() ||
      lexer->identifierEquals(FnvHash::Constants::RECURSIVE))
  {
    lexer->nextToken();
    withQueryClause->setRecursive(BOOL::TRUE);
  }

  for (;;)
  {
    SQLWithSubqueryClause_Entry_ptr entry = SQLWithSubqueryClause_Entry_ptr(new SQLWithSubqueryClause_Entry());
    entry->setParent(withQueryClause);

    string_ptr alias = make_string_ptr(encode_util::UnicodeToUTF8(*this->lexer->stringVal()));
    lexer->nextToken();
    entry->setAlias(alias);

    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();
      exprParser->names(entry->getColumns());
      accept(Token::RPAREN);
    }

    accept(Token::AS);
    accept(Token::LPAREN);

    if (lexer->token()->name->c_str() == Token::SELECT.name->c_str() ||
        lexer->token()->name->c_str() == Token::LPAREN.name->c_str() ||
        lexer->token()->name->c_str() == Token::WITH.name->c_str() ||
        lexer->token()->name->c_str() == Token::FROM.name->c_str())
    {
      entry->setSubQuery(select());
    }

    accept(Token::RPAREN);

    withQueryClause->addEntry(entry);

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }

    break;
  }

  return withQueryClause;
}